Respect TTY availability when running the dev server - #144
Conversation
executeCommand() enables TTY mode whenever the caller has not asked for
non-interactive mode, without checking whether a TTY is actually
available. In any environment without one — CI, a scripted deploy, an
editor task runner, a background shell — Symfony throws before the
process starts:
TTY mode requires /dev/tty to be read/writable.
at vendor/symfony/process/Process.php:1087
This makes `native:run` and `native:serve` unusable outside an
interactive terminal. `--no-interaction` does not help, because it is
only threaded through to the dependency install; the dev server call
still requests a TTY.
BuildCommand already guards this with Process::isTtySupported(), so this
applies the same check here and keeps the two paths consistent.
|
I'm not clear when you would be using |
|
Fair question, and checking it properly showed the PR is unnecessary.
$this->runDeveloper(
...
withoutInteraction: $this->option('no-interaction'), // RunCommand.php:66
);I verified The description's claim that the flag reached only the dependency install was wrong — I read that call site and assumed the other. Sorry for the noise, and thanks for pushing back rather than merging it. Closing. |
Running
php artisan native:run(ornative:serve) outside an interactive terminal fails before the process starts:ExecuteCommand::executeCommand()enables TTY mode whenever the caller has not explicitly asked for non-interactive mode, without checking whether a TTY is actually available:So the dev server cannot be started from CI, a scripted deploy, an editor task runner, or any background shell.
--no-interactiondoes not help: it is threaded through to the dependency install, but thedevinvocation still requests a TTY.BuildCommandalready guards against this (BuildCommand.php:183):This applies the same
isTtySupported()check inexecuteCommand(), so both paths behave consistently. Where a TTY exists the behaviour is unchanged; where none exists the process now runs with piped output instead of throwing.Verifying
With this change,
php artisan native:runstarts normally in a non-interactive shell where it previously aborted at the TTY check. Without it, the same invocation needs a pseudo-terminal wrapper (script -q /dev/null php artisan native:run) as a workaround.Pint and PHPStan pass on the changed file.